home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / dev / lang / Python16_Src.lha / Python16_Source / Modules / bsddbmodule.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-08-03  |  18.5 KB  |  851 lines

  1. /* Berkeley DB interface.
  2.    Author: Michael McLay
  3.    Hacked: Guido van Rossum
  4.    Btree and Recno additions plus sequence methods: David Ely
  5.  
  6.    XXX To do:
  7.    - provide interface to the B-tree and record libraries too
  8.    - provide a way to access the various hash functions
  9.    - support more open flags
  10.  
  11.    The windows port of the Berkeley DB code is hard to find on the web:
  12.    www.nightmare.com/software.html
  13. */
  14.  
  15. #include "Python.h"
  16. #ifdef WITH_THREAD
  17. #include "pythread.h"
  18. #endif
  19.  
  20. #include <sys/types.h>
  21. #include <sys/stat.h>
  22. #include <fcntl.h>
  23. #include <db.h>
  24. /* Please don't include internal header files of the Berkeley db package
  25.    (it messes up the info required in the Setup file) */
  26.  
  27. typedef struct {
  28.     PyObject_HEAD
  29.     DB *di_bsddb;
  30.     int di_size;    /* -1 means recompute */
  31. #ifdef WITH_THREAD
  32.     PyThread_type_lock di_lock;
  33. #endif
  34. } bsddbobject;
  35.  
  36. staticforward PyTypeObject Bsddbtype;
  37.  
  38. #define is_bsddbobject(v) ((v)->ob_type == &Bsddbtype)
  39. #define check_bsddbobject_open(v) if ((v)->di_bsddb == NULL) \
  40.                { PyErr_SetString(BsddbError, "BSDDB object has already been closed"); \
  41.                  return NULL; }
  42.  
  43. static PyObject *BsddbError;
  44.  
  45. static PyObject *
  46. newdbhashobject(file, flags, mode,
  47.         bsize, ffactor, nelem, cachesize, hash, lorder)
  48.     char *file;
  49.         int flags;
  50.         int mode;
  51.         int bsize;
  52.         int ffactor;
  53.         int nelem;
  54.         int cachesize;
  55.         int hash; /* XXX ignored */
  56.         int lorder;
  57. {
  58.     bsddbobject *dp;
  59.     HASHINFO info;
  60.  
  61.     if ((dp = PyObject_New(bsddbobject, &Bsddbtype)) == NULL)
  62.         return NULL;
  63.  
  64.     info.bsize = bsize;
  65.     info.ffactor = ffactor;
  66.     info.nelem = nelem;
  67.     info.cachesize = cachesize;
  68.     info.hash = NULL; /* XXX should derive from hash argument */
  69.     info.lorder = lorder;
  70.  
  71. #ifdef O_BINARY
  72.     flags |= O_BINARY;
  73. #endif
  74.     Py_BEGIN_ALLOW_THREADS
  75.     dp->di_bsddb = dbopen(file, flags, mode, DB_HASH, &info);
  76.     Py_END_ALLOW_THREADS
  77.     if (dp->di_bsddb == NULL) {
  78.         PyErr_SetFromErrno(BsddbError);
  79. #ifdef WITH_THREAD
  80.         dp->di_lock = NULL;
  81. #endif
  82.         Py_DECREF(dp);
  83.         return NULL;
  84.     }
  85.  
  86.     dp->di_size = -1;
  87. #ifdef WITH_THREAD
  88.     dp->di_lock = PyThread_allocate_lock();
  89.     if (dp->di_lock == NULL) {
  90.         PyErr_SetString(BsddbError, "can't allocate lock");
  91.         Py_DECREF(dp);
  92.         return NULL;
  93.     }
  94. #endif
  95.  
  96.     return (PyObject *)dp;
  97. }
  98.  
  99. static PyObject *
  100. newdbbtobject(file, flags, mode,
  101.           btflags, cachesize, maxkeypage, minkeypage, psize, lorder)
  102.     char *file;
  103.         int flags;
  104.         int mode;
  105.         int btflags;
  106.         int cachesize;
  107.         int maxkeypage;
  108.         int minkeypage;
  109.         int psize;
  110.         int lorder;
  111. {
  112.     bsddbobject *dp;
  113.     BTREEINFO info;
  114.  
  115.     if ((dp = PyObject_New(bsddbobject, &Bsddbtype)) == NULL)
  116.         return NULL;
  117.  
  118.     info.flags = btflags;
  119.     info.cachesize = cachesize;
  120.     info.maxkeypage = maxkeypage;
  121.     info.minkeypage = minkeypage;
  122.     info.psize = psize;
  123.     info.lorder = lorder;
  124.     info.compare = 0; /* Use default comparison functions, for now..*/
  125.     info.prefix = 0;
  126.  
  127. #ifdef O_BINARY
  128.     flags |= O_BINARY;
  129. #endif
  130.     Py_BEGIN_ALLOW_THREADS
  131.     dp->di_bsddb = dbopen(file, flags, mode, DB_BTREE, &info);
  132.     Py_END_ALLOW_THREADS
  133.     if (dp->di_bsddb == NULL) {
  134.         PyErr_SetFromErrno(BsddbError);
  135. #ifdef WITH_THREAD
  136.         dp->di_lock = NULL;
  137. #endif
  138.         Py_DECREF(dp);
  139.         return NULL;
  140.     }
  141.  
  142.     dp->di_size = -1;
  143. #ifdef WITH_THREAD
  144.     dp->di_lock = PyThread_allocate_lock();
  145.     if (dp->di_lock == NULL) {
  146.         PyErr_SetString(BsddbError, "can't allocate lock");
  147.         Py_DECREF(dp);
  148.         return NULL;
  149.     }
  150. #endif
  151.  
  152.     return (PyObject *)dp;
  153. }
  154.  
  155. static PyObject *
  156. newdbrnobject(file, flags, mode,
  157.           rnflags, cachesize, psize, lorder, reclen, bval, bfname)
  158.     char *file;
  159.         int flags;
  160.         int mode;
  161.         int rnflags;
  162.         int cachesize;
  163.         int psize;
  164.         int lorder;
  165.         size_t reclen;
  166.         u_char bval;
  167.         char *bfname;
  168. {
  169.     bsddbobject *dp;
  170.     RECNOINFO info;
  171.  
  172.     if ((dp = PyObject_New(bsddbobject, &Bsddbtype)) == NULL)
  173.         return NULL;
  174.  
  175.     info.flags = rnflags;
  176.     info.cachesize = cachesize;
  177.     info.psize = psize;
  178.     info.lorder = lorder;
  179.     info.reclen = reclen;
  180.     info.bval = bval;
  181.     info.bfname = bfname;
  182.  
  183. #ifdef O_BINARY
  184.     flags |= O_BINARY;
  185. #endif
  186.     Py_BEGIN_ALLOW_THREADS
  187.     dp->di_bsddb = dbopen(file, flags, mode, DB_RECNO, &info);
  188.     Py_END_ALLOW_THREADS
  189.     if (dp->di_bsddb == NULL) {
  190.         PyErr_SetFromErrno(BsddbError);
  191. #ifdef WITH_THREAD
  192.         dp->di_lock = NULL;
  193. #endif
  194.         Py_DECREF(dp);
  195.         return NULL;
  196.     }
  197.  
  198.     dp->di_size = -1;
  199. #ifdef WITH_THREAD
  200.     dp->di_lock = PyThread_allocate_lock();
  201.     if (dp->di_lock == NULL) {
  202.         PyErr_SetString(BsddbError, "can't allocate lock");
  203.         Py_DECREF(dp);
  204.         return NULL;
  205.     }
  206. #endif
  207.  
  208.     return (PyObject *)dp;
  209. }
  210.  
  211. static void
  212. bsddb_dealloc(dp)
  213.     bsddbobject *dp;
  214. {
  215. #ifdef WITH_THREAD
  216.     if (dp->di_lock) {
  217.         PyThread_acquire_lock(dp->di_lock, 0);
  218.         PyThread_release_lock(dp->di_lock);
  219.         PyThread_free_lock(dp->di_lock);
  220.         dp->di_lock = NULL;
  221.     }
  222. #endif
  223.     if (dp->di_bsddb != NULL) {
  224.         int status;
  225.         Py_BEGIN_ALLOW_THREADS
  226.         status = (dp->di_bsddb->close)(dp->di_bsddb);
  227.         Py_END_ALLOW_THREADS
  228.         if (status != 0)
  229.             fprintf(stderr,
  230.                 "Python bsddb: close errno %d in dealloc\n",
  231.                 errno);
  232.     }
  233.     PyObject_Del(dp);
  234. }
  235.  
  236. #ifdef WITH_THREAD
  237. #define BSDDB_BGN_SAVE(_dp) Py_BEGIN_ALLOW_THREADS PyThread_acquire_lock(_dp->di_lock,1);
  238. #define BSDDB_END_SAVE(_dp) PyThread_release_lock(_dp->di_lock); Py_END_ALLOW_THREADS
  239. #else
  240. #define BSDDB_BGN_SAVE(_dp) Py_BEGIN_ALLOW_THREADS 
  241. #define BSDDB_END_SAVE(_dp) Py_END_ALLOW_THREADS
  242. #endif
  243.  
  244. static int
  245. bsddb_length(dp)
  246.     bsddbobject *dp;
  247. {
  248.         if (dp->di_bsddb == NULL) {
  249.                  PyErr_SetString(BsddbError, "BSDDB object has already been closed"); 
  250.                  return -1; 
  251.         }
  252.     if (dp->di_size < 0) {
  253.         DBT krec, drec;
  254.         int status;
  255.         int size = 0;
  256.         BSDDB_BGN_SAVE(dp)
  257.         for (status = (dp->di_bsddb->seq)(dp->di_bsddb,
  258.                           &krec, &drec,R_FIRST);
  259.              status == 0;
  260.              status = (dp->di_bsddb->seq)(dp->di_bsddb,
  261.                           &krec, &drec, R_NEXT))
  262.             size++;
  263.         BSDDB_END_SAVE(dp)
  264.         if (status < 0) {
  265.             PyErr_SetFromErrno(BsddbError);
  266.             return -1;
  267.         }
  268.         dp->di_size = size;
  269.     }
  270.     return dp->di_size;
  271. }
  272.  
  273. static PyObject *
  274. bsddb_subscript(dp, key)
  275.     bsddbobject *dp;
  276.         PyObject *key;
  277. {
  278.     int status;
  279.     DBT krec, drec;
  280.     char *data,buf[4096];
  281.     int size;
  282.     PyObject *result;
  283.  
  284.     if (!PyArg_Parse(key, "s#", &data, &size))
  285.         return NULL;
  286.         check_bsddbobject_open(dp);
  287.     
  288.     krec.data = data;
  289.     krec.size = size;
  290.  
  291.     BSDDB_BGN_SAVE(dp)
  292.     status = (dp->di_bsddb->get)(dp->di_bsddb, &krec, &drec, 0);
  293.     if (status == 0) {
  294.         if (drec.size > sizeof(buf)) data = malloc(drec.size);
  295.         else data = buf;
  296.         memcpy(data,drec.data,drec.size);
  297.     }
  298.     BSDDB_END_SAVE(dp)
  299.     if (status != 0) {
  300.         if (status < 0)
  301.             PyErr_SetFromErrno(BsddbError);
  302.         else
  303.             PyErr_SetObject(PyExc_KeyError, key);
  304.         return NULL;
  305.     }
  306.  
  307.     result = PyString_FromStringAndSize(data, (int)drec.size);
  308.     if (data != buf) free(data);
  309.     return result;
  310. }
  311.  
  312. static int
  313. bsddb_ass_sub(dp, key, value)
  314.     bsddbobject *dp;
  315.         PyObject *key, *value;
  316. {
  317.     int status;
  318.     DBT krec, drec;
  319.     char *data;
  320.     int size;
  321.  
  322.     if (!PyArg_Parse(key, "s#", &data, &size)) {
  323.         PyErr_SetString(PyExc_TypeError,
  324.                 "bsddb key type must be string");
  325.         return -1;
  326.     }
  327.         if (dp->di_bsddb == NULL) {
  328.                  PyErr_SetString(BsddbError, "BSDDB object has already been closed"); 
  329.                  return -1; 
  330.         }
  331.     krec.data = data;
  332.     krec.size = size;
  333.     dp->di_size = -1;
  334.     if (value == NULL) {
  335.         BSDDB_BGN_SAVE(dp)
  336.         status = (dp->di_bsddb->del)(dp->di_bsddb, &krec, 0);
  337.         BSDDB_END_SAVE(dp)
  338.     }
  339.     else {
  340.         if (!PyArg_Parse(value, "s#", &data, &size)) {
  341.             PyErr_SetString(PyExc_TypeError,
  342.                     "bsddb value type must be string");
  343.             return -1;
  344.         }
  345.         drec.data = data;
  346.         drec.size = size;
  347. #if 0
  348.         /* For RECNO, put fails with 'No space left on device'
  349.            after a few short records are added??  Looks fine
  350.            to this point... linked with 1.85 on Solaris Intel
  351.            Roger E. Masse 1/16/97
  352.          */
  353.         printf("before put data: '%s', size: %d\n",
  354.                drec.data, drec.size);
  355.         printf("before put key= '%s', size= %d\n",
  356.                krec.data, krec.size);
  357. #endif
  358.         BSDDB_BGN_SAVE(dp)
  359.         status = (dp->di_bsddb->put)(dp->di_bsddb, &krec, &drec, 0);
  360.         BSDDB_END_SAVE(dp)
  361.     }
  362.     if (status != 0) {
  363.         if (status < 0)
  364.             PyErr_SetFromErrno(BsddbError);
  365.         else
  366.             PyErr_SetObject(PyExc_KeyError, key);
  367.         return -1;
  368.     }
  369.     return 0;
  370. }
  371.  
  372. static PyMappingMethods bsddb_as_mapping = {
  373.     (inquiry)bsddb_length,        /*mp_length*/
  374.     (binaryfunc)bsddb_subscript,    /*mp_subscript*/
  375.     (objobjargproc)bsddb_ass_sub,    /*mp_ass_subscript*/
  376. };
  377.  
  378. static PyObject *
  379. bsddb_close(dp, args)
  380.     bsddbobject *dp;
  381.         PyObject *args;
  382. {
  383.     if (!PyArg_NoArgs(args))
  384.         return NULL;
  385.     if (dp->di_bsddb != NULL) {
  386.         int status;
  387.         BSDDB_BGN_SAVE(dp)
  388.         status = (dp->di_bsddb->close)(dp->di_bsddb);
  389.         BSDDB_END_SAVE(dp)
  390.         if (status != 0) {
  391.             dp->di_bsddb = NULL;
  392.             PyErr_SetFromErrno(BsddbError);
  393.             return NULL;
  394.         }
  395.     }
  396.     dp->di_bsddb = NULL;
  397.     Py_INCREF(Py_None);
  398.     return Py_None;
  399. }
  400.  
  401. static PyObject *
  402. bsddb_keys(dp, args)
  403.     bsddbobject *dp;
  404.         PyObject *args;
  405. {
  406.     PyObject *list, *item;
  407.     DBT krec, drec;
  408.     char *data=NULL,buf[4096];
  409.     int status;
  410.     int err;
  411.  
  412.     if (!PyArg_NoArgs(args))
  413.         return NULL;
  414.     check_bsddbobject_open(dp);
  415.     list = PyList_New(0);
  416.     if (list == NULL)
  417.         return NULL;
  418.     BSDDB_BGN_SAVE(dp)
  419.     status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec, &drec, R_FIRST);
  420.     if (status == 0) {
  421.         if (krec.size > sizeof(buf)) data = malloc(krec.size);
  422.         else data = buf;
  423.         memcpy(data,krec.data,krec.size);
  424.     }
  425.     BSDDB_END_SAVE(dp)
  426.     while (status == 0) {
  427.         item = PyString_FromStringAndSize(data, (int)krec.size);
  428.         if (data != buf) free(data);
  429.         if (item == NULL) {
  430.             Py_DECREF(list);
  431.             return NULL;
  432.         }
  433.         err = PyList_Append(list, item);
  434.         Py_DECREF(item);
  435.         if (err != 0) {
  436.             Py_DECREF(list);
  437.             return NULL;
  438.         }
  439.         BSDDB_BGN_SAVE(dp)
  440.         status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec, &drec, R_NEXT);
  441.         if (status == 0) {
  442.             if (krec.size > sizeof(buf)) data = malloc(krec.size);
  443.             else data = buf;
  444.             memcpy(data,krec.data,krec.size);
  445.         }
  446.         BSDDB_END_SAVE(dp)
  447.     }
  448.     if (status < 0) {
  449.         PyErr_SetFromErrno(BsddbError);
  450.         Py_DECREF(list);
  451.         return NULL;
  452.     }
  453.     if (dp->di_size < 0)
  454.         dp->di_size = PyList_Size(list); /* We just did the work */
  455.     return list;
  456. }
  457.  
  458. static PyObject *
  459. bsddb_has_key(dp, args)
  460.     bsddbobject *dp;
  461.         PyObject *args;
  462. {
  463.     DBT krec, drec;
  464.     int status;
  465.     char *data;
  466.     int size;
  467.  
  468.     if (!PyArg_Parse(args, "s#", &data, &size))
  469.         return NULL;
  470.     check_bsddbobject_open(dp);
  471.     krec.data = data;
  472.     krec.size = size;
  473.  
  474.     BSDDB_BGN_SAVE(dp)
  475.     status = (dp->di_bsddb->get)(dp->di_bsddb, &krec, &drec, 0);
  476.     BSDDB_END_SAVE(dp)
  477.     if (status < 0) {
  478.         PyErr_SetFromErrno(BsddbError);
  479.         return NULL;
  480.     }
  481.  
  482.     return PyInt_FromLong(status == 0);
  483. }
  484.  
  485. static PyObject *
  486. bsddb_set_location(dp, key)
  487.     bsddbobject *dp;
  488.         PyObject *key;
  489. {
  490.     int status;
  491.     DBT krec, drec;
  492.     char *data,buf[4096];
  493.     int size;
  494.     PyObject *result;
  495.  
  496.     if (!PyArg_Parse(key, "s#", &data, &size))
  497.         return NULL;
  498.     check_bsddbobject_open(dp);
  499.     krec.data = data;
  500.     krec.size = size;
  501.  
  502.     BSDDB_BGN_SAVE(dp)
  503.     status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec, &drec, R_CURSOR);
  504.     if (status == 0) {
  505.         if (drec.size > sizeof(buf)) data = malloc(drec.size);
  506.         else data = buf;
  507.         memcpy(data,drec.data,drec.size);
  508.     }
  509.     BSDDB_END_SAVE(dp)
  510.     if (status != 0) {
  511.         if (status < 0)
  512.             PyErr_SetFromErrno(BsddbError);
  513.         else
  514.             PyErr_SetObject(PyExc_KeyError, key);
  515.         return NULL;
  516.     }
  517.  
  518.     result = Py_BuildValue("s#s#", krec.data, krec.size, data, drec.size);
  519.     if (data != buf) free(data);
  520.     return result;
  521. }
  522.  
  523. static PyObject *
  524. bsddb_seq(dp, args, sequence_request)
  525.     bsddbobject *dp;
  526.         PyObject *args;
  527.         int sequence_request;
  528. {
  529.     int status;
  530.     DBT krec, drec;
  531.     char *kdata=NULL,kbuf[4096];
  532.     char *ddata=NULL,dbuf[4096];
  533.     PyObject *result;
  534.  
  535.     if (!PyArg_NoArgs(args))
  536.         return NULL;
  537.  
  538.     check_bsddbobject_open(dp);
  539.     krec.data = 0;
  540.     krec.size = 0;
  541.  
  542.     BSDDB_BGN_SAVE(dp)
  543.     status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec,
  544.                      &drec, sequence_request);
  545.     if (status == 0) {
  546.         if (krec.size > sizeof(kbuf)) kdata = malloc(krec.size);
  547.         else kdata = kbuf;
  548.         memcpy(kdata,krec.data,krec.size);
  549.         if (drec.size > sizeof(dbuf)) ddata = malloc(drec.size);
  550.         else ddata = dbuf;
  551.         memcpy(ddata,drec.data,drec.size);
  552.     }
  553.     BSDDB_END_SAVE(dp)
  554.     if (status != 0) {
  555.         if (status < 0)
  556.             PyErr_SetFromErrno(BsddbError);
  557.         else
  558.             PyErr_SetObject(PyExc_KeyError, args);
  559.         return NULL;
  560.     }
  561.  
  562.     result = Py_BuildValue("s#s#", kdata, krec.size, ddata, drec.size);
  563.     if (kdata != kbuf) free(kdata);
  564.     if (ddata != dbuf) free(ddata);
  565.     return result;
  566. }
  567.  
  568. static PyObject *
  569. bsddb_next(dp, key)
  570.     bsddbobject *dp;
  571.         PyObject *key;
  572. {
  573.     return bsddb_seq(dp, key, R_NEXT);
  574. }
  575. static PyObject *
  576. bsddb_previous(dp, key)
  577.     bsddbobject *dp;
  578.         PyObject *key;
  579. {
  580.     return bsddb_seq(dp, key, R_PREV);
  581. }
  582. static PyObject *
  583. bsddb_first(dp, key)
  584.     bsddbobject *dp;
  585.         PyObject *key;
  586. {
  587.     return bsddb_seq(dp, key, R_FIRST);
  588. }
  589. static PyObject *
  590. bsddb_last(dp, key)
  591.     bsddbobject *dp;
  592.         PyObject *key;
  593. {
  594.     return bsddb_seq(dp, key, R_LAST);
  595. }
  596. static PyObject *
  597. bsddb_sync(dp, args)
  598.     bsddbobject *dp;
  599.         PyObject *args;
  600. {
  601.     int status;
  602.  
  603.     if (!PyArg_NoArgs(args))
  604.         return NULL;
  605.     check_bsddbobject_open(dp);
  606.     BSDDB_BGN_SAVE(dp)
  607.     status = (dp->di_bsddb->sync)(dp->di_bsddb, 0);
  608.     BSDDB_END_SAVE(dp)
  609.     if (status != 0) {
  610.         PyErr_SetFromErrno(BsddbError);
  611.         return NULL;
  612.     }
  613.     return PyInt_FromLong(status = 0);
  614. }
  615. static PyMethodDef bsddb_methods[] = {
  616.     {"close",        (PyCFunction)bsddb_close},
  617.     {"keys",        (PyCFunction)bsddb_keys},
  618.     {"has_key",        (PyCFunction)bsddb_has_key},
  619.     {"set_location",    (PyCFunction)bsddb_set_location},
  620.     {"next",        (PyCFunction)bsddb_next},
  621.     {"previous",    (PyCFunction)bsddb_previous},
  622.     {"first",        (PyCFunction)bsddb_first},
  623.     {"last",        (PyCFunction)bsddb_last},
  624.     {"sync",        (PyCFunction)bsddb_sync},
  625.     {NULL,               NULL}        /* sentinel */
  626. };
  627.  
  628. static PyObject *
  629. bsddb_getattr(dp, name)
  630.     PyObject *dp;
  631.         char *name;
  632. {
  633.     return Py_FindMethod(bsddb_methods, dp, name);
  634. }
  635.  
  636. static PyTypeObject Bsddbtype = {
  637.     PyObject_HEAD_INIT(NULL)
  638.     0,
  639.     "bsddb",
  640.     sizeof(bsddbobject),
  641.     0,
  642.     (destructor)bsddb_dealloc, /*tp_dealloc*/
  643.     0,            /*tp_print*/
  644.     (getattrfunc)bsddb_getattr, /*tp_getattr*/
  645.     0,            /*tp_setattr*/
  646.     0,            /*tp_compare*/
  647.     0,            /*tp_repr*/
  648.     0,            /*tp_as_number*/
  649.     0,            /*tp_as_sequence*/
  650.     &bsddb_as_mapping,    /*tp_as_mapping*/
  651. };
  652.  
  653. static PyObject *
  654. bsdhashopen(self, args)
  655.     PyObject *self;
  656.         PyObject *args;
  657. {
  658.     char *file;
  659.     char *flag = NULL;
  660.     int flags = O_RDONLY;
  661.     int mode = 0666;
  662.     int bsize = 0;
  663.     int ffactor = 0;
  664.     int nelem = 0;
  665.     int cachesize = 0;
  666.     int hash = 0; /* XXX currently ignored */
  667.     int lorder = 0;
  668.  
  669.     if (!PyArg_ParseTuple(args, "s|siiiiiii:hashopen",
  670.                   &file, &flag, &mode,
  671.                   &bsize, &ffactor, &nelem, &cachesize,
  672.                   &hash, &lorder))
  673.         return NULL;
  674.     if (flag != NULL) {
  675.         /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
  676.         if (flag[0] == 'r')
  677.             flags = O_RDONLY;
  678.         else if (flag[0] == 'w')
  679.             flags = O_RDWR;
  680.         else if (flag[0] == 'c')
  681.             flags = O_RDWR|O_CREAT;
  682.         else if (flag[0] == 'n')
  683.             flags = O_RDWR|O_CREAT|O_TRUNC;
  684.         else {
  685.             PyErr_SetString(BsddbError,
  686.                 "Flag should begin with 'r', 'w', 'c' or 'n'");
  687.             return NULL;
  688.         }
  689.         if (flag[1] == 'l') {
  690. #if defined(O_EXLOCK) && defined(O_SHLOCK)
  691.             if (flag[0] == 'r')
  692.                 flags |= O_SHLOCK;
  693.             else
  694.                 flags |= O_EXLOCK;
  695. #else
  696.             PyErr_SetString(BsddbError,
  697.                      "locking not supported on this platform");
  698.             return NULL;
  699. #endif
  700.         }
  701.     }
  702.     return newdbhashobject(file, flags, mode,
  703.                    bsize, ffactor, nelem, cachesize, hash, lorder);
  704. }
  705.  
  706. static PyObject *
  707. bsdbtopen(self, args)
  708.     PyObject *self;
  709.         PyObject *args;
  710. {
  711.     char *file;
  712.     char *flag = NULL;
  713.     int flags = O_RDONLY;
  714.     int mode = 0666;
  715.     int cachesize = 0;
  716.     int maxkeypage = 0;
  717.     int minkeypage = 0;
  718.     int btflags = 0;
  719.     unsigned int psize = 0;
  720.     int lorder = 0;
  721.  
  722.     if (!PyArg_ParseTuple(args, "s|siiiiiii:btopen",
  723.                   &file, &flag, &mode,
  724.                   &btflags, &cachesize, &maxkeypage, &minkeypage,
  725.                   &psize, &lorder))
  726.         return NULL;
  727.     if (flag != NULL) {
  728.         /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
  729.         if (flag[0] == 'r')
  730.             flags = O_RDONLY;
  731.         else if (flag[0] == 'w')
  732.             flags = O_RDWR;
  733.         else if (flag[0] == 'c')
  734.             flags = O_RDWR|O_CREAT;
  735.         else if (flag[0] == 'n')
  736.             flags = O_RDWR|O_CREAT|O_TRUNC;
  737.         else {
  738.             PyErr_SetString(BsddbError,
  739.                    "Flag should begin with 'r', 'w', 'c' or 'n'");
  740.             return NULL;
  741.         }
  742.         if (flag[1] == 'l') {
  743. #if defined(O_EXLOCK) && defined(O_SHLOCK)
  744.             if (flag[0] == 'r')
  745.                 flags |= O_SHLOCK;
  746.             else
  747.                 flags |= O_EXLOCK;
  748. #else
  749.             PyErr_SetString(BsddbError,
  750.                     "locking not supported on this platform");
  751.             return NULL;
  752. #endif
  753.         }
  754.     }
  755.     return newdbbtobject(file, flags, mode,
  756.                  btflags, cachesize, maxkeypage, minkeypage,
  757.                  psize, lorder);
  758. }
  759.  
  760. static PyObject *
  761. bsdrnopen(self, args)
  762.     PyObject *self;
  763.         PyObject *args;
  764. {
  765.     char *file;
  766.     char *flag = NULL;
  767.     int flags = O_RDONLY;
  768.     int mode = 0666;
  769.     int cachesize = 0;
  770.     int rnflags = 0;
  771.     unsigned int psize = 0;
  772.     int lorder = 0;
  773.     size_t reclen = 0;
  774.     char  *bval = "";
  775.     char *bfname = NULL;
  776.  
  777.     if (!PyArg_ParseTuple(args, "s|siiiiiiss:rnopen",
  778.                   &file, &flag, &mode,
  779.                   &rnflags, &cachesize, &psize, &lorder,
  780.                   &reclen, &bval, &bfname))
  781.         return NULL;
  782.  
  783. # if 0
  784.     printf("file: %s\n", file);
  785.     printf("flag: %s\n", flag);
  786.     printf("mode: %d\n", mode);
  787.     printf("rnflags: 0x%x\n", rnflags);
  788.     printf("cachesize: %d\n", cachesize);
  789.     printf("psize: %d\n", psize);
  790.     printf("lorder: %d\n", 0);
  791.     printf("reclen: %d\n", reclen);
  792.     printf("bval: %c\n", bval[0]);
  793.     printf("bfname %s\n", bfname);
  794. #endif
  795.     
  796.     if (flag != NULL) {
  797.         /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
  798.         if (flag[0] == 'r')
  799.             flags = O_RDONLY;
  800.         else if (flag[0] == 'w')
  801.             flags = O_RDWR;
  802.         else if (flag[0] == 'c')
  803.             flags = O_RDWR|O_CREAT;
  804.         else if (flag[0] == 'n')
  805.             flags = O_RDWR|O_CREAT|O_TRUNC;
  806.         else {
  807.             PyErr_SetString(BsddbError,
  808.                    "Flag should begin with 'r', 'w', 'c' or 'n'");
  809.             return NULL;
  810.         }
  811.         if (flag[1] == 'l') {
  812. #if defined(O_EXLOCK) && defined(O_SHLOCK)
  813.             if (flag[0] == 'r')
  814.                 flags |= O_SHLOCK;
  815.             else
  816.                 flags |= O_EXLOCK;
  817. #else
  818.             PyErr_SetString(BsddbError,
  819.                     "locking not supported on this platform");
  820.             return NULL;
  821. #endif
  822.         }
  823.         else if (flag[1] != '\0') {
  824.             PyErr_SetString(BsddbError,
  825.                        "Flag char 2 should be 'l' or absent");
  826.             return NULL;
  827.         }
  828.     }
  829.     return newdbrnobject(file, flags, mode, rnflags, cachesize,
  830.                  psize, lorder, reclen, bval[0], bfname);
  831. }
  832.  
  833. static PyMethodDef bsddbmodule_methods[] = {
  834.     {"hashopen",    (PyCFunction)bsdhashopen, 1},
  835.     {"btopen",    (PyCFunction)bsdbtopen, 1},
  836.     {"rnopen",    (PyCFunction)bsdrnopen, 1},
  837.     {0,        0},
  838. };
  839.  
  840. DL_EXPORT(void)
  841. initbsddb() {
  842.     PyObject *m, *d;
  843.  
  844.     Bsddbtype.ob_type = &PyType_Type;
  845.     m = Py_InitModule("bsddb", bsddbmodule_methods);
  846.     d = PyModule_GetDict(m);
  847.     BsddbError = PyErr_NewException("bsddb.error", NULL, NULL);
  848.     if (BsddbError != NULL)
  849.         PyDict_SetItemString(d, "error", BsddbError);
  850. }
  851.